// MatrixRenderWidget.cpp
#include "MatrixRenderWidget.h"
#include <QMouseEvent>
#include <cmath>

// 顶点/片段着色器同原版……
static const char *vertexShaderSrc = R"(
#version 330 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec3 aColor;
uniform mat4 uMVP;
out vec3 vColor;
void main() {
    gl_Position = uMVP * vec4(aPos, 0.0, 1.0);
    vColor = aColor;
}
)";

// 片段着色器：输出插值后的颜色
static const char *fragmentShaderSrc = R"(
#version 330 core
in vec3 vColor;
out vec4 FragColor;
void main() {
    FragColor = vec4(vColor, 1.0);
}
)";

MatrixRenderWidget::MatrixRenderWidget(QWidget *parent)
    : QOpenGLWidget(parent)
    , vbo(QOpenGLBuffer::VertexBuffer)
{
    setFixedSize(800, 600);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

}

MatrixRenderWidget::~MatrixRenderWidget() {
    makeCurrent();
    vao.destroy();
    vbo.destroy();
    doneCurrent();
}

void MatrixRenderWidget::initializeGL() {
    initializeOpenGLFunctions();
    glClearColor(1,1,1,1);
    initShaders();
    initGeometry();     // 只初始化坐标轴等静态数据
    updateMatrices();
}

void MatrixRenderWidget::resizeGL(int w, int h) {
    glViewport(0,0,w,h);
    float aspect = float(w) / float(h);
    projection.setToIdentity();
    projection.ortho(-aspect, aspect, -1, 1, -1, 1);
    updateMatrices();
}

void MatrixRenderWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.bind();
    shaderProgram.setUniformValue("uMVP", projection * view * model);

    // 1. 画静态坐标轴（4 个顶点）
    vao.bind();
    glDrawArrays(GL_LINES, 0, 4);
    vao.release();
    // 绘制分度值
    drawAxisTicksAndLabels();

    // 2. 动态绘制：向量和矩阵
    if (displaySum_) {
        drawSumVectors();
    }
    if (displayMatrix_) {
        drawMatrixVectors();
    }


    shaderProgram.release();
}

void MatrixRenderWidget::mousePressEvent(QMouseEvent *ev) {
    lastPos = ev->pos();
}

void MatrixRenderWidget::mouseMoveEvent(QMouseEvent *ev) {
    QPoint delta = ev->pos() - lastPos;
    lastPos = ev->pos();

    panX += 2.0f * delta.x() / width();
    panY -= 2.0f * delta.y() / height();

    view.setToIdentity();
    view.translate(panX, panY, 0);
    view.scale(scaleFactor, scaleFactor, 1);
    update();
}

void MatrixRenderWidget::wheelEvent(QWheelEvent *ev) {
    float num = ev->angleDelta().y() / 120.0f;
    scaleFactor *= std::pow(1.1f, num);

    view.setToIdentity();
    view.translate(panX, panY, 0);
    view.scale(scaleFactor, scaleFactor, 1);
    update();
}

void MatrixRenderWidget::keyPressEvent(QKeyEvent *ev) {
    if (ev->key() == Qt::Key_Plus)      scaleFactor *= 1.1f;
    else if (ev->key() == Qt::Key_Minus) scaleFactor /= 1.1f;

    view.setToIdentity();
    view.translate(panX, panY, 0);
    view.scale(scaleFactor, scaleFactor, 1);
    update();
}

void MatrixRenderWidget::initShaders() {
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,   vertexShaderSrc);
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSrc);
    shaderProgram.link();
}

void MatrixRenderWidget::drawArrow(GLfloat* arrow) {
    QOpenGLBuffer tmpVbo(QOpenGLBuffer::VertexBuffer);
    QOpenGLVertexArrayObject tmpVao;
    tmpVao.create();
    tmpVao.bind();
    tmpVbo.create();
    tmpVbo.bind();
    tmpVbo.allocate(arrow, sizeof(arrow));

    shaderProgram.enableAttributeArray(0);
    shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 2, 2 * sizeof(GLfloat));

    glLineWidth(2.0f);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glLineWidth(1.0f);

    tmpVbo.release();
    tmpVao.release();
}

void MatrixRenderWidget::drawAxisArrows() {
    // X 轴箭头（在右端）
    GLfloat arrowX[] = {
        1.0f, 0.05f,  1.2f, 0.1f,   1.0f, -0.05f    // 箭头三角形
    };
    drawArrow(arrowX);

    // Y 轴箭头（在上端）
    GLfloat arrowY[] = {
        0.05f, 1.0f,   0.1f, 1.2f,    -0.05f, 1.0f    // 箭头三角形
    };
    drawArrow(arrowY);
}

void MatrixRenderWidget::initGeometry() {
    // 只设置坐标轴顶点：X 轴 (2 点)、Y 轴 (2 点)
    GLfloat axisVerts[] = {
        -1, 0, 1,0,0,   +1, 0, 1,0,0,
        0,-1, 0,1,0,    0,+1, 0,1,0
    };

    vao.create(); vao.bind();
    vbo.create(); vbo.bind();
    vbo.allocate(axisVerts, sizeof(axisVerts));

    shaderProgram.enableAttributeArray(0);
    shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 2, 5 * sizeof(GLfloat));

    shaderProgram.enableAttributeArray(1);
    shaderProgram.setAttributeBuffer(1, GL_FLOAT, 2 * sizeof(GLfloat), 3, 5 * sizeof(GLfloat));

    vbo.release();
    drawAxisArrows();
}

void MatrixRenderWidget::drawSumVectors() {
    // 使用临时 VBO/VAO 绘制两条向量（v1, v2）和它们的和
    QVector2D v1(vector1_), v2(vector2_), sum = v1 + v2;
    GLfloat verts[] = {
        0,0,   v1.x(), v1.y(),
        0,0,   v2.x(), v2.y(),
        0,0,   sum.x(), sum.y()
    };

    QOpenGLVertexArrayObject tmpVao;
    QOpenGLBuffer tmpVbo(QOpenGLBuffer::VertexBuffer);
    tmpVao.create(); tmpVao.bind();
    tmpVbo.create(); tmpVbo.bind();
    tmpVbo.allocate(verts, sizeof(verts));

    shaderProgram.enableAttributeArray(0);
    shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 2, 4 * sizeof(GLfloat));

    glLineWidth(2.0f);
    glDrawArrays(GL_LINES, 0, 6);
    glLineWidth(1.0f);

    tmpVbo.release(); tmpVao.release();
}

void MatrixRenderWidget::drawMatrixVectors() {
    // 绘制矩阵作用在基向量 (1,0) 和 (0,1) 上的结果
    QMatrix4x4 M;
    M.setRow(0, QVector4D(matrix_.x(), matrix_.y(), 0, 0));
    M.setRow(1, QVector4D(matrix_.z(), matrix_.w(), 0, 0));
    QVector2D u = (M * QVector4D(1,0,0,1)).toVector2D();
    QVector2D v = (M * QVector4D(0,1,0,1)).toVector2D();

    GLfloat verts[] = {
        0,0, u.x(), u.y(),
        0,0, v.x(), v.y()
    };

    QOpenGLVertexArrayObject tmpVao2;
    QOpenGLBuffer tmpVbo2(QOpenGLBuffer::VertexBuffer);
    tmpVao2.create(); tmpVao2.bind();
    tmpVbo2.create(); tmpVbo2.bind();
    tmpVbo2.allocate(verts, sizeof(verts));

    shaderProgram.enableAttributeArray(0);
    shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 2, 4 * sizeof(GLfloat));

    glLineWidth(2.0f);
    glDrawArrays(GL_LINES, 0, 4);
    glLineWidth(1.0f);

    tmpVbo2.release(); tmpVao2.release();
}


void MatrixRenderWidget::updateMatrices() {
    model.setToIdentity();
}

void MatrixRenderWidget::showVectorSum(const QPointF &v1, const QPointF &v2) {
    vector1_ = v1;
    vector2_ = v2;
    displaySum_ = true;
    update();
}

void MatrixRenderWidget::showMatrixTransform(const QVector4D &m) {
    matrix_ = m;
    displayMatrix_ = true;
    update();
}

